﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.ServiceModel;
using System.Web;
using SecurityClient;

namespace SecurityModule.Workflows
{
    class WFPostHomeResetYubikey : SimpleWorkflow
    {
        public WFPostHomeResetYubikey()
        {
            Verb = "POST";
            Path = "/Home/ResetYubikey";
        }
        public override void PreProcessImplementation(HttpContext context)
        {
            // verify token, store details of the account pending approval and add Email and ClientCode to Request.Form
            var callback = new Func<string, string>(content =>
            {
                //Read the form fields and white list them.
                var fields = HttpUtility.ParseQueryString(content);

                //Read fields
                var tokenId = fields["ResetToken"];
                var password = fields["Password"];
                var yubikeyOTP = fields["YubikeyOTP"];

                //Whitelist the following fields to prevent password from being sidebanded.
                string[] whitelistFields = { "ResetToken", "Email", "Password" };
                foreach (var key in fields.AllKeys.Where(key => !whitelistFields.Contains(key)))
                {
                    fields.Remove(key);
                }

                var hasErrors = false;
                if (string.IsNullOrEmpty(tokenId))
                {
                    fields.Add("EXTERRMSG", "Missing Yubikey reset token");
                    hasErrors = true;
                }
                if (string.IsNullOrEmpty(password))
                {
                    fields.Add("EXTERR_NewPassword", "Please provide a password");
                    hasErrors = true;
                }
                if (hasErrors)
                {
                    return fields.ToString();
                }
                try
                {
                    //Anon is attempting to confirm their identity
                    var security = new SecurityServiceProxy();
                    var email = security.GetTokenFieldValue(tokenId, "EmailAddress") as string;
                    if (string.IsNullOrEmpty(email))
                    {
                        // send up an error to the application
                        fields.Add("EXTERRMSG", "Invalid Yubikey reset token");
                    }
                    else // token is verified
                    {
                        fields.Add("Email", email);

                        // store a token for reset Yubikey (will be used when approved)
                        var result = security.RequestYubikeyReset(email, password, tokenId, yubikeyOTP);

                        if (result.Success)
                        {
                            fields.Add("Token", result.TokenId);
                            fields["Password"] = "nothing";
                        }
                        else
                        {
                            fields["Password"] = "error";
                            //Bubble up an error to the application
                            fields.Add("EXTERRMSG", result.ErrorMessage);
                        }
                    }
                }
                catch (Exception exception)
                {
                    if (exception is PipeException || exception is EndpointNotFoundException)
                    {
                        //If the security service is offline or broken
                        if (fields.AllKeys.Contains("EXTERRMSG"))
                        {
                            fields["EXTERRMSG"] = SecurityServiceDownMsg;
                        }
                        else
                        {
                            fields.Add("EXTERRMSG", SecurityServiceDownMsg);
                        }
                    }
                    else
                    {
                        if (fields.AllKeys.Contains("EXTERRMSG"))
                        {
                            fields["EXTERRMSG"] = exception.Message;
                        }
                        else
                        {
                            fields.Add("EXTERRMSG", exception.Message);
                        }
                    }
                }

                return fields.ToString();
            });
            context.Request.Filter = new RequestFilter(context.Request.Filter, context.Request.ContentEncoding, callback);

            context.Response.Filter = new ReplaceFilter(context.Response.Filter, context.Response.ContentEncoding,
                new Dictionary<string, string>
                    {
                        {
                            "{{YubikeyOTP}}",
                            @"<label class='control-label' for='YubikeyOTP'>New Yubikey</label><input name='YubikeyOTP' type='text' class='form-control'>"
                        }
                    }
                );
        }

        public override void PostProcessImplementation(HttpContext context)
        {
            // No post-processing
        }
    }
}
